package pl.poznan.put.cs.idss.particlefilter.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.Timer;

import pl.poznan.put.cs.idss.particlefilter.agent.Agent;
import pl.poznan.put.cs.idss.particlefilter.agent.Particle;
import pl.poznan.put.cs.idss.particlefilter.enviroment.Lighthouse;
import pl.poznan.put.cs.idss.particlefilter.enviroment.WorldMap;
import pl.poznan.put.cs.idss.particlefilter.filter.ParticleFilter;

/**
 * Główny element okna aplikacji - rysuje całą grafikę, odpowiada za animacje.
 * 
 * @author Kornel Lewandowski
 * 
 */
public class Board extends JPanel implements ActionListener, MouseListener {

	private static final long serialVersionUID = 1812154094986428836L;

	private WorldMap map;
	private Agent agent;
	private ParticleFilter particleFilter;
	private List<Lighthouse> lighthouses = new ArrayList<Lighthouse>();

	private Timer repaintTimer;

	/**
	 * Konstruktor - ustawia nową mape świata, latarnię i agenta.
	 * 
	 * @throws Exception
	 */
	public Board() throws Exception {
		map = new WorldMap(800, 400);
		map.relateBoard(this);
		addLighthouse(new Lighthouse(map, -5, -5));
		addLighthouse(new Lighthouse(map, -5, 405));
		addLighthouse(new Lighthouse(map, 785, -5));
		addLighthouse(new Lighthouse(map, 785, 405));
		addLighthouse(new Lighthouse(map, 385, -5));
		addLighthouse(new Lighthouse(map, 385, 405));
		addMouseListener(this);
		setAgent(new Agent(map));
		setParticleFilter(0);
		setRepaintTimer(new Timer(40, this));
		getRepaintTimer().start();
		stop();
	}

	public void setParticleFilter(int particles) throws InterruptedException,
			IOException {
		particleFilter = new ParticleFilter(agent, particles);
		particleFilter.start();
	}

	/**
	 * Przeciążona metoda - rysuje obiekty na mapie.
	 */
	@Override
	protected void paintComponent(Graphics gx) {
		super.paintComponent(gx);
		Image buffer = createImage(900, 400);
		Graphics g = buffer.getGraphics();
		g.fillRect(0, 0, 900, 400);
		g.drawImage(map.getWorldMapImage(), 0, 0, this);
		g.drawImage(map.getBorderImage(), 0, 0, this);
		g.setColor(agent.getColor());
		if (particleFilter != null) {
			for (Particle p : particleFilter.getParticles()) {
				g.setColor(new Color(50, 255, 50));
				g.drawOval(p.getX(), p.getY(), 3, 3);
			}
		}
		g.drawImage(agent.getAgentImage(), getAgent().getX(),
				getAgent().getY(), this);
		for (Lighthouse l : lighthouses) {
			g.drawImage(l.getLighthouseImage(), l.getX() - 300, l.getY() - 300,
					this);
		}
		gx.drawImage(buffer, 0, 0, this);
	}

	public Image getMapImage() {
		return map.getWorldMapImage();
	}

	/**
	 * Wywoływana co określony interwał czasu. Wewnątrz metoda repaint(), która
	 * wywołuje przerysowywanie okna.
	 */
	public void actionPerformed(ActionEvent e) {
		repaint();
	}

	public Agent getAgent() {
		return agent;
	}

	public void setAgent(Agent agent) {
		this.agent = agent;
	}

	public List<Lighthouse> getLighthouses(boolean isLight) {
		List<Lighthouse> list = new ArrayList<Lighthouse>();
		for (Lighthouse l : lighthouses) {
			if (l.isLighting() == isLight)
				list.add(l);
		}
		return list;
	}

	public void addLighthouse(Lighthouse lighthouse) {
		lighthouses.add(lighthouse);
	}

	public void mouseClicked(MouseEvent e) {
		for (Lighthouse l : lighthouses) {
			if ((Math.abs(e.getX() - l.getX()) < 30)
					&& (Math.abs(e.getY() - l.getY()) < 30)) {
				l.switchImage();
			}
		}
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public Timer getRepaintTimer() {
		return repaintTimer;
	}

	public void setRepaintTimer(Timer repaintTimer) {
		this.repaintTimer = repaintTimer;
	}

	public void start() {
		repaintTimer.start();
		particleFilter.getTimer().start();
	}

	public void stop() {
		repaintTimer.stop();
		particleFilter.getTimer().stop();
	}

}
